using System;
using System.Collections.Generic;
using System.Text;

using Mono.Cecil;
using Mono.Cecil.Cil;

namespace CILUtil
{
    /// <summary>
    /// TODO: Merge with Field Stat, or extract from FieldStat.
    /// </summary>
    public class CodeProperties
    {
        public static string GetMethodNameWithParametersTight(MethodReference method, bool tight)
        {
            if (method.Parameters.Count == 0)
            {
                return tight? method.Name + "()" : method.Name + " ()";
            }
            // Monocov output for overloaded methods look like:
            // MethodName (string,byte[],System.Data.DataTable)
            // MethodName (string,int)
            string[] paramList = new string[method.Parameters.Count];
            int i = 0;
            foreach (ParameterDefinition param in method.Parameters)
            {
                paramList[i] = GetParameterName(param);
                i++;
            }
            if (tight)
            {
                return method.Name + "(" + string.Join(",", paramList) + ")";
            }
            else
            {   // Monocov format.
                return method.Name + " (" + string.Join(",", paramList) + ")";
            }
        }

        // format uses full name for non-value types
        // for types with alias, the alias is used: int32 -> int
        // TODO: Fix for ref.
        public static string GetParameterName(ParameterDefinition param)
        {
            if (param.ParameterType == null)
                return param.ToString();
            try
            {
                if (param.ParameterType.IsValueType ||
                    param.ParameterType.FullName == "System.Object" ||
                    param.ParameterType.FullName == "System.String")
                {
                    string name = param.ParameterType.Name.ToLower();
                    if (name.IndexOf("16") > -1 ||
                        name.IndexOf("32") > -1 ||
                        name.IndexOf("64") > -1)
                    {
                        name = name.Replace("16", "");
                        name = name.Replace("32", "");
                        name = name.Replace("64", "");
                    }
                    return name;
                }
                else
                    return param.ParameterType.FullName;
            }
            catch
            {
                return param.ToString();
            }
        }

        public static string GetClassName(TypeReference type)
        {
            // Trim off Generic Parameters to classes.  e.g. System.Collections.Generic.List`1<MyFirstClass> =>
            // System.Collections.Generic.List
            if (type.FullName.Contains("`"))
            {
                return type.FullName.Remove(type.FullName.IndexOf("`"));
            }
            return type.FullName;
        }


        public static bool IsBlockEnd(Instruction instruction)
        {
            switch (instruction.OpCode.FlowControl)
            {
                case FlowControl.Branch:
                case FlowControl.Cond_Branch:
                case FlowControl.Break:
                case FlowControl.Return:
                case FlowControl.Throw:
                    return true;
                default:
                    return false;
            }
        }
    }
}
